Curso de ScriptVox Intermedirio - Aula 15 - Prof. Oswaldo Vernet - iNCE/UFRJ

Esta aula encerra o curso intermedirio. Baixem a nova verso do interpretador.

Os comandos SE e ENQUANTO possuem em comum o fato de avaliarem a expresso que
os segue; dependendo do valor obtido nesta avaliao, o fluxo de execuo pode
sofrer um desvio para uma linha do script distinta da linha seguinte quela 
que contm o comando.

A diferena entre estes dois comandos est no aspecto iterativo. O comando
SE em sua verso no compacta far a avaliao da expresso apenas uma vez, 
tomando a deciso de continuar na linha seguinte se a expresso for verdadeira 
(isto , diferente de zero) ou de desviar para a linha onde se encontra a 
clusula SENO correspondente, caso ela exista, ou para a linha onde se 
encontra o comando FIM SE correspondente. 

J o comando ENQUANTO age diferentemente: se a expresso for falsa (isto , 
igual a zero), o fluxo  desviado para o comando FIM ENQUANTO correspondente; 
se for verdadeira, o fluxo direciona-se para a linha seguinte  do comando 
ENQUANTO, dando incio  execuo do BLOCO do comando, e prossegue at que o 
comando FIM ENQUANTO correspondente seja atingido; neste momento, ocorre um 
desvio implcito de volta  linha do comando ENQUANTO, causando nova avaliao 
da expresso. Este processo se repetir at que a expresso seja avaliada como 
falsa (isto , igual a zero).

A ideia desta aula  examinar atentamente as espcies de expresses que podemos
utilizar nestes dois comandos. Em princpio, elas devem produzir um resultado do tipo
inteiro quando avaliadas, que ser considerado falso se for zero ou verdadeiro se
for diferente de zero.  comum encontrar nestas expresses certos operadores ditos
RELACIONAIS, que estabelecem comparaes entre valores. So eles: o operador de
igualdade "=", o operador de no igualdade "<>", o operador maior ">", o operador
maior ou igual ">=", o operador menor "<" e o operador menor ou igual "<=".
Todos estes operadores, quando aplicados a valores para os quais a comparao
faa sentido, produzem como resultado o inteiro um (se a comparao for verdadeira)
ou o inteiro zero (se a comparao for falsa).

Alm destes seis, existem os operadores ditos de INCLUSO, aplicveis a cadeias ou
a listas, que foram objeto de exame na aula anterior. So eles: o operador "comea por", 
simbolizado por "=*", o operador "termina por", simbolizado por "*=" e o operador "contm",
simbolizado por "*=*". Estes tambm produzem como resultado os valores zero ou um,
significando falso e verdadeiro, respectivamente.

Para introduzirmos os trs operadores que faltam, vamos resolver o seguinte exerccio:
construir a funo faz_pergunta, que recebe como parmetro uma cadeia contendo uma pergunta
a ser feita ao usurio. A funo dever escrever na tela a cadeia e, sem mudar de linha,
esperar que o usurio digite sim ou no como resposta. A resposta poder ser em portugus
ou em ingls, isto : se o usurio digitar "S", "SIM", "Y" ou "YES", a funo dever
retornar o inteiro um, significando verdadeiro; se o usurio digitar "N", "NO" ou "NO",
a funo dever retornar zero, significando falso. Se o usurio no digitar nenhuma
dessas palavras, o usurio deve ser insultado e a pergunta, repetida. Maisculas e 
minsculas devem ser igualmente tratadas.

Segue-se um primeiro esboo da funo faz_pergunta:

* incio da funo faz_pergunta
funo faz_pergunta (pergunta) : resposta
@incio
	escreve pergunta &
	l MAIUSC resposta
	se resposta = "S"   retorna 1
	se resposta = "SIM" retorna 1
	se resposta = "Y"   retorna 1
	se resposta = "YES" retorna 1
	se resposta = "N"   retorna 0
	se resposta = "NO" retorna 0
	se resposta = "NO"  retorna 0
	escreve "Imbecil, responde direito!"
	desvia @incio
fim funo
* fim da funo faz_pergunta

A varivel "resposta" tem escopo local porque s precisa existir enquanto a funo
faz_pergunta estiver sendo executada. Quem chamar a funo estar interessado na resposta
zero ou um, e no no que o usurio digitou.

Bom, isto  o que escreveramos at a verso 5.0 do ScriptVox. Na verso 6.0, introduzimos
os operadores LGICOS, que permitem reunir, em uma s expresso, diversos testes.
Vejamos o primeiro deles, que se aplica ao exemplo dado. 

O operador lgico "OU" aplica-se a operandos inteiros e realiza a DISJUNO LGICA entre
seus operandos: se os dois operandos so falsos (isto , zero), o resultado ser falso; 
do contrrio, o resultado ser verdadeiro. Utilizamos este operador quando desejamos saber se 
pelo menos uma das condies participantes da disjuno  verdadeira, j que ele s produz 
o valor falso se todas forem falsas. 

Portanto, podemos substituir a srie de comandos SE no script por apenas dois comandos. 
A nova funo faz_pergunta  mostrada a seguir:

* incio da funo faz_pergunta
funo faz_pergunta (pergunta) : resposta
@incio
	escreve pergunta &
	l MAIUSC resposta
	se resposta = "S" ou resposta = "SIM" ou resposta = "Y" ou resposta = "YES" retorna 1
	se resposta = "N" ou resposta = "NO" ou resposta = "NO"  retorna 0
	escreve "Imbecil, responde direito!"
	desvia @incio
fim funo
* fim da funo faz_pergunta

Para introduzirmos o segundo operador, vamos a um outro exemplo. Em um script, precisamos
testar se uma pessoa nasceu entre 1950 e 1970. A funo testa_ano, detalhada a seguir,
cumpre esta tarefa, retornando verdadeiro caso o ano dado como parmetro esteja na faixa
especificada ou falso caso contrrio:

* incio da funo testa_ano
funo testa_ano (ano)
	se ano < 1950 retorna 0
	se ano > 1970 retorna 0
	retorna 1
fim funo
* fim da funo testa_ano
  
O operador lgico "E" aplica-se a operandos inteiros e realiza a conjuno lgica entre os
seus operandos, isto : se um dos operandos  falsos (isto , zero), o resultado ser falso; 
do contrrio o resultado ser verdadeiro. Utilizamos este operador quando desejamos saber se 
todas as condies participantes da conjuno so verdadeiras, j que ele s produz o valor 
falso se alguma for falsa. 

A funo testa_ano pode ser assim reescrita:

* incio da funo testa_ano
funo testa_ano (ano)
	se ano >= 1950 e ano <= 1970 retorna 1
	retorna 0
fim funo
* fim da funo testa_ano

Ou ainda, de forma mais compacta:

* incio da funo testa_ano
funo testa_ano (ano)
	retorna ano >= 1950 e ano <= 1970
fim funo
* fim da funo testa_ano

A conjuno lgica tem precedncia sobre a disjuno; ou seja, o operador "e" tem precedncia 
sobre o operador "ou". Portanto, na expresso a seguir:

x > 0 ou y >= 0 e y <= 3

a disjuno no ser entre as condies "x > 0" e "y >= 0", como aparenta, mas entre a condio
"x > 0" e o resultado da conjuno entre "y >= 0" e "y <= 3". Na dvida, use parnteses para 
impor a ordem de avaliao que voc desejar.

Um ltimo exemplo nos levar a uma expresso mista em que os parnteses sero necessrios para
impor uma ordem de avaliao distinta da que  imposta pela precedncia natural entre os operadores 
"e" e "ou".

Devemos construir a funo "bissexto", que recebe como parmetro um inteiro e testa se ele 
correspnode a um ano bissexto; se for, a funo dever retornar um; se no for, dever retornar
zero.

Sabemos que um ano bissexto  necessariamente mltiplo de 4. Porm, nem todos os anos mltiplos
de 4 so bissextos. Por exemplo: 1900 no foi bissexto, mas 2000 foi. A regra  a seguinte:
para que um ano seja bissexto ele deve ser mltiplo de 4; se, alm disso, ele for tambm 
mltiplo de 100, a centena (isto , o quociente do ano por 100) deve ser par.

Para testar se um nmero  mltiplo de outro, usamos o operador RESTO DA DIVISO, simbolizado
por "%". Assim, um nmero X ser mltiplo de Y se, e somente se, o resto da diviso de X por
Y for zero. Portanto, se o resto for diferente de zero,  porque X no  mltiplo de Y.

Ento, nosso raciocnio para construir a funo  o seguinte: se o ano no for mltiplo de 4,
certamente ele no ser bissexto e, neste caso, retornamos zero. Se ele for mltiplo de 4, 
ele poder ou no ser bissexto. Temos que verificar se ele tambm  mltiplo de 100.  Se no
for, ele  um ano bissexto; se for, devemos verificar se o quociente do ano por cem  par,
ou seja, mltiplo de 2. Se for par, o ano  bissexto; se no for, o ano no  bissexto.

A funo ficaria assim: 

* incio da funo bissexto
funo bissexto (ano)
	se ano % 4 <> 0   retorna 0         ; se no  mltiplo de 4, no  bissexto
* a execuo s chega aqui se o ano for mltiplo de 4
	se ano % 100 <> 0 retorna 1			; se  mltiplo de 4 mas no  de 100,  bissexto
* a execuo s chega aqui se o ano for mltiplo 100 (e, portanto, tambm mltiplo de 4)
	se (ano / 100) % 2 = 0 retorna 1	; se  mltiplo de 4 e de 100 com centena par,  bissexto
* a execuo s chega aqui se o ano for mltiplo de 100 (e tambm de 4,  claro) com centena mpar
	retorna 0							; se  mltiplo de 4 e de 100 com centena mpar, no  bissexto
fim funo 
* incio da funo bissexto

Utilizando os operadores "e" e "ou", a funo bissexto pode ser assim reescrita:

* incio da funo bissexto
funo bissexto (ano)
	se ano % 4 = 0 e (ano % 100 <> 0 ou (ano / 100) % 2 = 0) retorna 1
	retorna 0
fim funo 
* incio da funo bissexto

Observando mais atentamente esta ltima verso da funo bissexto, podemos simplific-la
ainda mais:

* incio da funo bissexto
funo bissexto (ano)
	retorna  ano % 4 = 0 e (ano % 100 <> 0 ou (ano / 100) % 2 = 0)
fim funo 
* incio da funo bissexto


EXERCCIOS

Exerccios de Estudo Dirigido

1. Utilizando o operador "contm", aplicado a listas, as expresses que aparecem nos comandos SE da
   verso melhorada da funo faz_pergunta podem ser simplificadas. Mostre como.
				
2. Faa o mesmo para a funo faz_pergunta.

3. O operador unrio de negao lgica, simbolizado pelo identificador "NO", tem o seguinte
   efeito: se o operando que o segue for verdadeiro, o operador produz o resultado falso e
   vice-versa. O Teorema de De Morgan (o segundo De no est repetido, faz parte do nome do
   matemtico), conhecido na lgica, permite converter uma conjuno lgica na negao de uma
   disjuno, e vice-versa. Por exemplo, a expresso

		x > 3 e x < 10

   equivale a

		no (x <= 3 ou x >= 10)

   Da mesma forma, a expresso

        x < 10 ou x > 20

   equivale a

        no (x >= 10 e x <= 20)

   Pesquise sobre o Teorema de De Morgan.


Exerccio de avaliao (enviar para scriptvox@gmail.com at o meio-dia de 12 de maro de 2012)

Escreva um script que l do teclado duas datas, ambas no formato dd/mm/aaaa. O script dever testar
se a primeira data  anterior  segunda e, em caso afirmativo, calcular o nmero de dias decorridos
entre as duas. Por exemplo, se as datas forem 01/03/1920 e 05/03/1920, a resposta dever ser 4.
Se a primeira data for igual ou posterior  segunda, o script dever apenas relatar este fato.

Cuidado com os anos bissextos!

Bom estudo! 

Oswaldo Vernet
